package com.example.rbac.common;

import com.example.rbac.util.JsonMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;

/**
 * @author XieLongzhen
 * @date 2018/12/26 18:46
 */
@Slf4j
public class HttpInterceptor extends HandlerInterceptorAdapter {

    private ThreadLocal<Long> startTime = new ThreadLocal<>();

    /**
     * 预处理回调方法，实现处理器的预处理（如检查登陆），第三个参数为响应的处理器，自定义Controller
     * <p>
     * 返回值：
     * true表示继续流程（如调用下一个拦截器或处理器）
     * false表示流程中断（如登录检查失败），不会继续调用其他的拦截器或处理器
     * 此时我们需要通过response来产生响应；
     *
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        startTime.set(System.currentTimeMillis());
        String url = request.getRequestURI().toString();
        Map paramMap = request.getParameterMap();
        log.info("Request start. url:{}, params:{}", url, JsonMapper.obj2Str(paramMap));
        return super.preHandle(request, response, handler);
    }

    /**
     * 当请求成功时进行后置处理
     * <p>
     * 实现处理器的后处理（但在渲染视图之前）
     * 此时我们可以通过modelAndView（模型和视图对象）对模型数据进行处理或对视图进行处理
     * modelAndView也可能为null。
     *
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        log.info("Request finished.");
        super.postHandle(request, response, handler, modelAndView);
    }

    /**
     * 在任何情况下都会对返回的请求做处理
     * <p>
     * 即在视图渲染完毕时回调，如性能监控中我们可以在此记录结束时间并输出消耗时间
     * 还可以进行一些资源清理，类似于try-catch-finally中的finally，但仅调用处理器执行链中
     *
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("Request completed. Time costed: {}", System.currentTimeMillis() - startTime.get());
        super.afterCompletion(request, response, handler, ex);
        removeThreadLocalInfo();
    }

    public void removeThreadLocalInfo() {
        RequestHolder.remove();
    }
}
